/*
 * fml_flash.c
 *
 *  Created on: 2025年4月8日
 *      Author: 22332
 */

#include <stdio.h>
#include "cola_init.h"
#include "cola_device.h"
#include "cola_os.h"
#include "fml_flash.h"
#include "shell.h"

uint8_t buff[8] = {1,2,3,4,5,6,0,0};
static cola_device_t *g_pDevflash = NULL;
extern void logWrite(const char *fmt, ...);
const int address_test = 0;
#define VENDOR_CRC32_DEFAULT_VALUE      (0xF0F0F0F0)

/* Initialization of flash buffers */
ST_VENDOR_DATA gst_vendor_A_data;
ST_VENDOR_DATA gst_vendor_B_data;

ST_VENDOR_DATA gst_factory_data =
{
	.crc32 = 0x0F0F0F0F,
	.mcu_upgrade_flag = 0x01,		///< MCU的升级标志
	.screen_brightness = 0x02,		///< 屏幕亮度
	.PN_VERSION0 = '3',
	.PN_VERSION1 = '3',
	.PN_VERSION2 = '3',
	.PN_VERSION3 = '3',
	.PN_VERSION4 = '3',
	.PN_VERSION5 = '3',

	.HARDWARE_VERSION0 = '4',
	.HARDWARE_VERSION1 = '4',
	.HARDWARE_VERSION2 = '4',
	.HARDWARE_VERSION3 = '4',
	.HARDWARE_VERSION4 = '4',
	.HARDWARE_VERSION5 = '4',

	.SOFTWARE_VERSION0 = '5',
	.SOFTWARE_VERSION1 = '5',
	.SOFTWARE_VERSION2 = '5',
	.SOFTWARE_VERSION3 = '5',
	.SOFTWARE_VERSION4 = '5',
	.SOFTWARE_VERSION5 = '5',

	.TFT_SW_VERSION0 = '6',
	.TFT_SW_VERSION1 = '6',
	.TFT_SW_VERSION2 = '6',
	.TFT_SW_VERSION3 = '6',
	.TFT_SW_VERSION4 = '6',

	.TFT_HW_VERSION0 = '7',
	.TFT_HW_VERSION1 = '7',
	.TFT_HW_VERSION2 = '7',
	.TFT_HW_VERSION3 = '7',
	.TFT_HW_VERSION4 = '7',

	.DH_SW_VERSION0 = '8',
	.DH_SW_VERSION1 = '8',
	.DH_SW_VERSION2 = '8',
	.DH_SW_VERSION3 = '8',
	.DH_SW_VERSION4 = '8',

	.DH_HW_VERSION0 = '9',
	.DH_HW_VERSION1 = '9',
	.DH_HW_VERSION2 = '9',
	.DH_HW_VERSION3 = '9',
	.DH_HW_VERSION4 = '9',
	.host_ack_upgrade= 0x00,//是否由host导致的升级复位标志
};


uint32_t Utils_CRC32(const uint8_t *data, size_t len)
{
    uint32_t crc = 0xFFFFFFFF;
    uint8_t byte = 0;
    while (len--)
    {
        byte = *data++;
        crc ^= byte;
        for (int j = 0; j < 8; j++)
        {
            uint32_t mask = -(crc & 1);
            crc = (crc >> 1) ^ (0xEDB88320 & mask);
        }
    }
    return ~crc;
}

void vendor_factory_set(void)
{
    gst_vendor_A_data = gst_factory_data;
    gst_vendor_B_data = gst_factory_data;
    vendor_data_save();
}

static uint8_t vendor_verify_data(ST_VENDOR_DATA *verify_data, uint16_t dataLen)
{
    uint32_t read_crc32 = verify_data->crc32;
    uint32_t verify_crc32 = 0;
    verify_data->crc32 = VENDOR_CRC32_DEFAULT_VALUE;
    verify_crc32 = Utils_CRC32((const uint8_t *)verify_data, dataLen);
    verify_data->crc32 = read_crc32;
    logWrite("read_crc32=0x%X,verify_crc32=0x%X\r\n",read_crc32,verify_crc32);
    if (verify_crc32 != read_crc32)
    {
        return 1;
    }
    return 0;
}

bool vendor_data_load(void)
{
	bool read_result = false;
    if (!g_pDevflash)
    {
        return read_result;
    }
   cola_device_read(g_pDevflash, A_vendor_address, &gst_vendor_A_data, sizeof(gst_vendor_A_data));
   cola_device_read(g_pDevflash, B_vendor_address, &gst_vendor_B_data, sizeof(gst_vendor_B_data));
   if (vendor_verify_data(&gst_vendor_A_data, sizeof(ST_VENDOR_DATA)) == 0)
   {
       if (vendor_verify_data(&gst_vendor_B_data, sizeof(ST_VENDOR_DATA)) == 0)
    	   read_result = true;
   }
   return read_result;
}

void vendor_data_save(void)
{
    if (!g_pDevflash)
    {
        return;
    }
    logWrite("gst_vendor_A_data len=%d\r\n",sizeof(gst_vendor_A_data));
    /* CRC32 calc. */
    gst_vendor_A_data.crc32 = VENDOR_CRC32_DEFAULT_VALUE;
    gst_vendor_A_data.crc32 = Utils_CRC32((const uint8_t *)&gst_vendor_A_data, sizeof(gst_vendor_A_data));
    cola_device_write(g_pDevflash, A_vendor_address, &gst_vendor_A_data, sizeof(gst_vendor_A_data));
    gst_vendor_B_data.crc32 = VENDOR_CRC32_DEFAULT_VALUE;
    gst_vendor_B_data.crc32 = Utils_CRC32((const uint8_t *)&gst_vendor_B_data, sizeof(gst_vendor_B_data));
    cola_device_write(g_pDevflash, B_vendor_address, &gst_vendor_B_data, sizeof(gst_vendor_B_data));
}

void fml_flash_write_upgrade(uint32_t address, uint8_t *buf,int length)//write 2048 byte
{
	cola_device_write(g_pDevflash,address,buf,length);
}

void fml_flash_read(uint32_t address, uint8_t *buf,uint8_t length)
{
	cola_device_read(g_pDevflash,address,buf,length);
}


void fml_flash_print_info(ST_VENDOR_DATA *pData)
{
	logWrite("crc32=0x%X\r\n",pData->crc32);
	logWrite("mcu_upgrade_flag=%d\r\n",pData->mcu_upgrade_flag);
	logWrite("screen_brightness=%d\r\n",pData->screen_brightness);
	logWrite("PN_VERSION[0~5]=%c%c%c%c%c%c\r\n",pData->PN_VERSION0,
												pData->PN_VERSION1,
												pData->PN_VERSION2,
												pData->PN_VERSION3,
												pData->PN_VERSION4,
												pData->PN_VERSION5);

	logWrite("HARDWARE_VERSION[0~5]=%c%c%c%c%c%c\r\n",pData->HARDWARE_VERSION0,
												pData->HARDWARE_VERSION1,
												pData->HARDWARE_VERSION2,
												pData->HARDWARE_VERSION3,
												pData->HARDWARE_VERSION4,
												pData->HARDWARE_VERSION5);

	logWrite("SOFTWARE_VERSION[0~5]=%c%c%c%c%c%c\r\n",pData->SOFTWARE_VERSION0,
												pData->SOFTWARE_VERSION1,
												pData->SOFTWARE_VERSION2,
												pData->SOFTWARE_VERSION3,
												pData->SOFTWARE_VERSION4,
												pData->SOFTWARE_VERSION5);

	logWrite("TFT_SW_VERSION[0~4]=%c%c%c%c%c\r\n",pData->TFT_SW_VERSION0,
												pData->TFT_SW_VERSION1,
												pData->TFT_SW_VERSION2,
												pData->TFT_SW_VERSION3,
												pData->TFT_SW_VERSION4);

	logWrite("TFT_HW_VERSION[0~4]=%c%c%c%c%c\r\n",pData->TFT_HW_VERSION0,
												pData->TFT_HW_VERSION1,
												pData->TFT_HW_VERSION2,
												pData->TFT_HW_VERSION3,
												pData->TFT_HW_VERSION4);

	logWrite("DH_SW_VERSION[0~4]=%c%c%c%c%c\r\n",pData->DH_SW_VERSION0,
												pData->DH_SW_VERSION1,
												pData->DH_SW_VERSION2,
												pData->DH_SW_VERSION3,
												pData->DH_SW_VERSION4);

	logWrite("DH_HW_VERSION[0~4]=%c%c%c%c%c\r\n",pData->DH_HW_VERSION0,
												pData->DH_HW_VERSION1,
												pData->DH_HW_VERSION2,
												pData->DH_HW_VERSION3,
												pData->DH_HW_VERSION4);
	logWrite("host_ack_upgrade=%d\r\n",pData->host_ack_upgrade);
}

void fml_flash_init(void)
{
	bool flash_result = false;
	g_pDevflash = cola_device_find("FLASH");
    if(g_pDevflash)
        cola_device_open(g_pDevflash, 0);
   // gst_vendor_A_data = gst_factory_data;
   //  vendor_data_save();
    flash_result = vendor_data_load();
    logWrite("flash_result=%d\r\n",flash_result);
    if(sizeof(ST_VENDOR_DATA)%8 != 0)
    {
    	while(1)
    		logWrite("ST_VENDOR_DATA size mod 8 must equal 0!!!!!!!!\r\n");
    }
    if(flash_result == false)
    {
    	gst_vendor_A_data = gst_factory_data;
    	gst_vendor_B_data = gst_factory_data;
    	vendor_data_save();
    	logWrite("restore factory\r\n");
    }
#if 0
    else
    {
    	fml_flash_print_info(&gst_vendor_A_data);
    	fml_flash_print_info(&gst_vendor_B_data);
    }

    if(gst_vendor_A_data.mcu_upgrade_flag == 1)
    	logWrite("current program partA = %d , 0x000%x\r\n",gst_vendor_A_data.mcu_upgrade_flag,&address_test);
    else if(gst_vendor_B_data.mcu_upgrade_flag == 1)
        logWrite("current program partB = %d , 0x000%x\r\n",gst_vendor_B_data.mcu_upgrade_flag,&address_test);
#endif
}

#if 0

uint8_t g_value = 0x00;
void fml_flash_write_test(uint8_t value)
{
	#define SIZE 			2048
	int i=0,j=0;
	uint8_t pWriteBuf[SIZE];
	int num = 16;
	logWrite("fml_flash_write_test:num=%d\r\n",num);
	for(j=0; j<num; j++)
	{
		for(i=0; i<sizeof(pWriteBuf); i++)
		{
			pWriteBuf[i] = g_value = value;
		}
		cola_device_write(g_pDevflash, D_FLASH_START_ADDRESS+j*SIZE, pWriteBuf, sizeof(pWriteBuf));
	}
}


void fml_flash_read_test(void)
{
	#define SIZE 			2048
	int i=0,j=0;
	uint8_t pReadBuf[SIZE];
	int num = 16;
	for(j=0; j<num; j++)
	{
		cola_device_read(g_pDevflash,D_FLASH_START_ADDRESS+j*SIZE,pReadBuf,sizeof(pReadBuf));
		for(i=0; i<sizeof(pReadBuf); i++)
		{
			if(g_value != pReadBuf[i])
			{
				logWrite("j=%d,not the same\r\n",j);
				break;
			}
		}
		if(i == sizeof(pReadBuf))
		{
			logWrite("Flash write and read the same,j=%d,addr=0x%X\r\n",j,D_FLASH_START_ADDRESS+j*SIZE);
		}
	}
}


void fml_flash_write_read_test(uint8_t value)
{//这里写完后读会死机,问题待查
	#define SIZE 			2048
	#define SECTOR_NUM		16
	int i=0,j=0;
	uint8_t pWriteBuf[SIZE];
	uint8_t pReadBuf[SIZE];
	int num = (SECTOR_NUM/(SIZE/1024));
	logWrite("num=%d\r\n",num);
	for(j=5; j<num; j++)
	{
		for(i=0; i<sizeof(pWriteBuf); i++)
		{
			pWriteBuf[i] = value;
			pReadBuf[i] = 0x00;
		}
		cola_device_write(g_pDevflash, D_FLASH_START_ADDRESS+j*SIZE, pWriteBuf, sizeof(pWriteBuf));
		cola_device_read(g_pDevflash,D_FLASH_START_ADDRESS+j*SIZE,pReadBuf,sizeof(pReadBuf));

		for(i=0; i<sizeof(pWriteBuf); i++)
		{
			if(pWriteBuf[i] != pWriteBuf[i])
			{
				logWrite("j=%d,not the same\r\n",j);
				break;
			}
		}
		if(i == sizeof(pWriteBuf))
		{
			logWrite("Flash write and read the same,j=%d,addr=0x%X\r\n",j,D_FLASH_START_ADDRESS+j*SIZE);
		}
	}
}

int flash(int argc, char *argv[])
{
	if (argc < 3)
	{
		logWrite("para length must greater than 3\r\n");
		return 0;
	}

	int mode = atoi(argv[1]);
	int value = atoi(argv[2]);
	if(mode == 0)
	{
		vendor_data_save();
		logWrite("vendor_data_save\r\n");
	}
	else if(mode == 1)
	{
		logWrite("vendor_data_load=%d,size=%d\r\n",vendor_data_load(),sizeof(gst_vendor_A_data));
	}
	else if(mode == 2)
	{
		logWrite("gst_vendor_A_data:\r\n");
		fml_flash_print_info(&gst_vendor_A_data);
	}
	else if(mode == 3)
	{
		logWrite("gst_vendor_B_data:\r\n");
		fml_flash_print_info(&gst_vendor_B_data);
	}
	else if(mode == 4)
	{
		gst_vendor_A_data.DH_HW_VERSION0 = value;
	}
	else if(mode == 5)
	{
		logWrite("fml_flash_write_read_test:0x%02X\r\n",value);
		fml_flash_write_read_test(value);
	}
	else if(mode == 6)
	{
		logWrite("fml_flash_write_test:0x%02X\r\n",value);
		fml_flash_write_test(value);
	}
	else if(mode == 7)
	{
		logWrite("fml_flash_read_test\r\n");
		fml_flash_read_test();
	}
	return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), flash, flash, flash,flash);
#endif
